<html>
  <head>
    <meta charset="utf-8">
    <title>Mongoose ODM</title>
    <style>
      body {
        background: url('/docs/2.7.x/images/bg.png');
        padding: 0 30px 30px;
        margin-top: 0;
      }

      #wrap {
        background: url('/docs/2.7.x/images/pattern.png') no-repeat -134px -211px;
        min-height: 600px;
        padding-top: 30px;
      }

      #page {
        width: 650px;
        margin: auto;
        position: relative;
      }

      #footer {
        font: 13px Helvetica;
        padding-top: 15px;
        border-top: 1px solid #000;
        color: #666;
        margin-top: 25px;
      }

      #footer > div {
        padding-top: 8px;
        float: right;
        text-align: right;
        padding-bottom: 20px;
      }

      #content {
        color: #111;
        font: 15px Courier;
      }

      #content h1, #content h2, #content h3 {
        text-shadow: 0 1px 0 #fff;
      }

      #announce {
        background: #2A758A;
        border: 10px solid black;
        border-radius: 7px;
        padding: 30px;
        font-size: 125%;
        color: white;
        text-shadow: none;
        font-family: Arial;
      }

      #announce a {
        color: orange;
        text-shadow: none;
      }

      pre {
        background: rgba(255,255,255,.8);
        border: 1px solid #c6c6c6;
        padding: 10px;
        border-radius: 3px;
        box-shadow: 1px 3px 6px #ddd;
      }

      code {
        background: rgba(255,255,255,.8);
        border: 1px solid #c6c6c6;
        color: #333;
        border-radius: 3px
      }

      pre code {
        border: 0 none;
      }

      form {
        font: bold 12px Helvetica;
        text-shadow: 0 1px 0 #fff;
        float: left;
        padding-bottom: 25px;
      }

      form img {
        margin-right: 5px
      }

      #google-members-count {
        vertical-align: top;
        line-height: 32px;
      }

      h1 a {
        background: url('/docs/2.7.x/images/logo.png');
        width: 404px;
        height: 47px;
        margin-bottom: 40px;
        text-indent: -500em;
        display: block;
      }

      a {
        color: #2a758a;
        text-shadow: 0 1px 0 #fff;
        text-decoration: none;
      }

      a:hover {
        opacity: 0.8;
      }

      #menu {
        position: fixed;
        top: 0;
        left: 0;
        height: 100%;
        background-color: rgba(0,0,0,0.3);
        font: bold 15px Helvetica;
        border-right: 1px solid rgba(0,0,0,0.2);
      }

      #menu ul {
        margin: 0;
        padding: 50px 0;
      }

      #menu ul li {
        list-style-type: none;
        padding-left: 15px;
        padding-right: 20px;
      }

      #menu ul li a {
        color: #fff;
        text-shadow: none;
      }
      #menu ul li a:hover {
        text-decoration: underline;
      }
      #wild { margin-top: 10px; }
    </style>

    <script>
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-1122274-9']);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
      })();
      
      function getMembers(data){
        if (!(data && data.query && data.query.results && data.query.results.p)) return;
        var members = document.createElement('span');
        members.id = 'google-members-count';
        members.innerHTML = '('+ data.query.results.p +' members)';
        document.getElementsByTagName('FORM')[0].insertBefore(members, document.getElementById('google-subscribe-input'));
      };

      window.onload = function(){
        // lame jsonp
        var script = document.createElement('script');
        script.src = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22http%3A%2F%2Fgroups.google.com%2Fgroup%2Fmongoose-orm%2Fabout%22%20and%20xpath%3D'%2F%2Fdiv%5B%40class%3D%5C'maincontbox%5C'%5D%2Ftable%2Ftr%5B1%5D%2Ftd%2Fp%5B1%5D'%0A&format=json&callback=getMembers";
        document.head.appendChild(script);
      };
    </script>
  </head>
  <body>
    <a href="http://github.com/learnboost/mongoose"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"></a>
    <div id="wrap">
      <div id="page">
        <div id="menu">
          <ul>
            <li><a href="../index.html">Home</a></li>
            <li><a href="model-definition.html">Models/Schemas</a></li>
            <li><a href="schematypes.html">Schema Types</a></li>
            <li><a href="schema-options.html">Schema Options</a></li>
            <li><a href="middleware.html">Middleware</a></li>
            <li><a href="finding-documents.html">Finding Docs</a></li>
            <li><a href="updating-documents.html">Updating Docs</a></li>
            <li><a href="query.html">Queries</a></li>
            <li><a href="querystream.html">Query Streams</a></li>
            <li><a href="methods-statics.html">Methods &amp; Statics</a>
            <li><a href="defaults.html">Defaults</a></li>
            <li><a href="indexes.html">Indexes</a></li>
            <li><a href="validation.html">Validation</a></li>
            <li><a href="virtuals.html">Virtuals</a></li>
            <li><a href="getters-setters.html">Getters / Setters</a></li>
            <li><a href="embedded-documents.html">Embedded Docs</a></li>
            <li><a href="populate.html">Populate (DBRef-like)</a></li>
            <li><a href="plugins.html">Plugins</a></li>
            <li><a href="errors.html">Errors</a></li>
            <li><a href="migration-1x-2x.html">v1x - v2x Migration</a></li>
            <li><a href="api.html">API</a></li>
          </ul>
        </div>

        <h1><a href="../index.html">Mongoose</a></h1>

        <div id="content">
          <!-- ANNOUNCE -->
          <h1>Populate - DBRef-like behavior</h1>

<p><code>ObjectIds</code> can now refer to another document in a collection within our database and be <code>populate()</code>d when querying. An example is helpful:</p>

<pre><code>var mongoose = require('mongoose')
  , Schema = mongoose.Schema

var PersonSchema = new Schema({
    name    : String
  , age     : Number
  , stories : [{ type: Schema.ObjectId, ref: 'Story' }]
});

var StorySchema = new Schema({
    _creator : { type: Schema.ObjectId, ref: 'Person' }
  , title    : String
  , fans     : [{ type: Schema.ObjectId, ref: 'Person' }]
});

var Story  = mongoose.model('Story', StorySchema);
var Person = mongoose.model('Person', PersonSchema);
</code></pre>

<p>So far we've created two models. Our <code>Person</code> model has it's <code>stories</code> field set to an array of <code>ObjectId</code>s. The <code>ref</code> option is what tells Mongoose in which model to look, in our case the <code>Story</code> model. All <code>_id</code>s we store here must be document <code>_id</code>s from the <code>Story</code> model. We also added a <code>_creator</code> <code>ObjectId</code> to our <code>Story</code> schema which refers to a single <code>Person</code>.</p>

<h2>Saving a ref (to the parent)</h2>

<p>Below you can see how we "save" a ref in 'story1' back to the _creator.  This <br />is usually all you need to do.</p>

<pre><code>var aaron = new Person({ name: 'Aaron', age: 100 });

aaron.save(function (err) {
  if (err) ...

  var story1 = new Story({
      title: "A man who cooked Nintendo"
    , _creator: aaron._id
  });

  story1.save(function (err) {
    if (err) ...
  });
})
</code></pre>

<h2>Populating the refs (to the parent)</h2>

<p>So far we haven't done anything special. We've merely created a <code>Person</code> and a <code>Story</code>. Now let's take a look at populating our story's <code>_creator</code>:</p>

<pre><code>Story
.findOne({ title: /Nintendo/i })
.populate('_creator') // &lt;--
.exec(function (err, story) {
  if (err) ..
  console.log('The creator is %s', story._creator.name);
  // prints "The creator is Aaron"
})
</code></pre>

<p>Yup that's it. We've just queried for a <code>Story</code> with the term Nintendo in it's title and also queried the <code>Person</code> collection for the story's creator. Nice!</p>

<p>Arrays of <code>ObjectId</code> refs work the same way. Just call the <code>populate</code> method on the query and an array of documents will be returned in place of the <code>ObjectId</code>s.</p>

<p>What if we only want a few specific fields returned for the query? This can be accomplished by passing an array of field names to the <code>populate</code> method:</p>

<pre><code>Story
.findOne({ title: /Nintendo/i })
.populate('_creator', ['name']) // &lt;-- only return the Persons name
.exec(function (err, story) {
  if (err) ..

  console.log('The creator is %s', story._creator.name);
  // prints "The creator is Aaron"

  console.log('The creators age is %s', story._creator.age)
  // prints "The creators age is null'
})
</code></pre>

<p>Now this is much better. The only property of the creator we are using is the <code>name</code> so we only returned that field from the db. Efficiency FTW!</p>

<p>Great, but what if we wanted to populate our <code>fans</code> array based on their age, and return, at most, any 5 of them?</p>

<pre><code>Story
.find(...)
.populate('fans', null, { age: { $gte: 21 }}, { limit: 5 })
</code></pre>

<p>Done. Conditions and options are the third and fourth arguments respectively.</p>

<h2>References to the children</h2>

<p>You may find however, if you use the <code>aaron</code> object, you are unable to get a list of the <code>stories</code>.  This is because no <code>story</code> objects were ever 'pushed' on to <code>aaron.stories</code>.</p>

<p>There are two perspectives to this story.  First, it's nice to have aaron know which are his stories.</p>

<pre><code>  aaron.stories.push(story1);
  aaron.save();
</code></pre>

<p>This allows you do a find &amp; populate like:</p>

<pre><code>Person
.findOne({ name: 'Aaron' })
.populate('stories') // &lt;-- only works if you pushed refs to children
.exec(function (err, person) {
  if (err) ..

  console.log('JSON for person is: ', person);
})
</code></pre>

<p>However, it is debatable that you really want two sets of pointers as they may get out of sync.  So you could instead merely find() the documents you are interested in.</p>

<pre><code>Story
.find({ _creator: aaron._id })
.populate('_creator') // &lt;-- not really necessary
.exec(function (err, stories) {
  if (err) ..

  console.log('The stories JSON is an array: ', stories);
})
</code></pre>

<h2>Updating</h2>

<p>Now that we have a story we realized that the <code>_creator</code> was incorrect. We can update <code>ObjectId</code> refs the same as any other property through the magic of Mongooses internal casting:</p>

<pre><code>var guille = new Person({ name: 'Guillermo' });
guille.save(function (err) {
  if (err) ..

  story._creator = guille; // or guille._id

  story.save(function (err) {
    if (err) ..

    Story
    .findOne({ title: /Nintendo/i })
    .populate('_creator', ['name'])
    .exec(function (err, story) {
      if (err) ..

      console.log('The creator is %s', story._creator.name)
      // prints "The creator is Guillermo"
    })

  })
})
</code></pre>

<h3>Note:</h3>

<p>The documents returned from calling <code>populate</code> become fully functional, <code>remove</code>able, <code>save</code>able documents. Do not confuse them with embedded docs. Take caution when calling its <code>remove</code> method because you'll be removing it from the database, not just the array.</p>
        </div>

        <div id="footer">

          <form action="http://groups.google.com/group/mongoose-orm/boxsubscribe">
           <a href="http://groups.google.com/group/mongoose-orm" id="google-subscribe-link"><img src="/docs/2.7.x/images/groups.png" border="0"></a>
           <span id="google-members-count">&nbsp;</span>
           <div id="google-subscribe-input">
             Email: <input type="text" name="email" id="google-subscribe-email">
             <input type="submit" name="go" value="Subscribe">
           </div>
          </form>

          <div>
            Mongoose by <a href="http://github.com/learnboost">LearnBoost Labs</a>.<br>
            Released under the MIT license.<br>
            Copyright <a href="http://learnboost.com">LearnBoost 2011</a>.
          </div>
        </div>
      </div>
    </div>
  </body>
</html>
